--- /dev/null
+# Testing ostree-boot on an existing system
+
+Start from an amd64 Debian system (9 or newer, as long as a backported
+ostree-boot package is available) - it will be switched to a Debian
+unstable (sid) OSTree-based installation as part of following these
+instructions. A VM is obviously most convenient, but bare metal should
+work equally.
+
+The installation needs to satisfy the following requirements:
+
+* It must have a separate /boot partition (this is a general libostree
+ limitation [1]).
+* The root partition must not be encrypted.
+* It must use GRUB and BIOS booting. Other bootloaders or EFI may require
+ different bootloader setup steps. [2]
+
+[1]: https://github.com/ostreedev/ostree/issues/1452
+[2]: https://pagure.io/workstation-ostree-config/blob/5b574d39c63b82b397df789eb4a75a5bdcc13dd0/f/README-install-inside.md
+
+We need the bootloader integration files on the non-OSTree system from
+which we are switching, as well as in the OSTree-based installation,
+so the bootloader gets configured properly when we "ostree admin deploy":
+
+ # apt-get update
+ # apt-get install ostree ostree-boot multistrap
+
+Create the ostree system repository and a stateroot:
+
+ # ostree admin init-fs /
+ # ostree admin os-init debian
+
+Copy modified-deb-ostree-builder, ostree-1.conf and ostree-2.conf from
+debian/ostree-boot-examples/ to the test machine, and run the builder
+script:
+
+ # chmod +x ./deb-ostree-builder
+ # ./deb-ostree-builder ./ostree-1.conf sid-1 /ostree/repo
+ # ./deb-ostree-builder ./ostree-2.conf sid-2 /ostree/repo
+
+If ostree-boot is not available in the target suite in the Debian
+archive yet, then you will need to edit ostree-1.conf and ostree-2.conf to
+remove ostree-boot from the bootstrap, and instead put the ostree-boot,
+ostree and libostree-1-1 packages in /root/extra-packages, and use
+modified-deb-ostree-builder instead of deb-ostree-builder. This is a
+temporary hack to solve the chicken-and-egg situation of not adding
+ostree-boot to the Debian archive until it is testable, but not being
+able to test it until it is in the archive.
+
+Then we deploy the first of those commits:
+
+ # ostree admin deploy --karg-proc-cmdline --os=debian os/debian/amd64/sid-1
+ # deploy=$(find /ostree/deploy/debian/deploy/* -maxdepth 0 -type d)
+
+Next, we set the root password and copy a few essential configuration files
+into the initial deployment:
+
+ # chroot $deploy passwd root
+ # : > $deploy/etc/machine-id
+ # for f in etc/fstab etc/default/grub; do cp /$f $deploy/$f; done
+
+Finally, we set up the bootloader by pointing GRUB at the configuration file
+managed by ostree. Alternatively, you can run update-grub by hand after every
+new ostree deployment. This step may be different or unnecessary for other
+bootloaders.
+
+ # mv /boot/grub/grub.cfg /boot/grub/grub.cfg.backup
+ # ln -s ../loader/grub.cfg /boot/grub/grub.cfg
+
+Now reboot. Make sure to select the new ostree entry in the bootloader. Log in
+as root using the password you selected before. The system is rather
+unconfigured (network access can be set up in /etc/network/interfaces). This is
+the commit built from the ostree-1.conf file, so it doesn't have the hello
+package:
+
+ # hello
+ -bash: hello: command not found
+
+Now we can deploy the second commit from inside the ostree system:
+
+ # ostree admin deploy --karg-proc-cmdline --os=debian os/debian/amd64/sid-2
+
+Reboot again. Note that your new deployment will again be the first ostree
+entry in the menu, labelled `ostree:0`. Your old deployment has been moved
+down the menu to `ostree:1`. The root password and the other configuration
+was copied from the first deployment, so you can log in as before.
+
+Now try running the hello command again:
+
+ # hello
+ Hello, world!
+
+This shows we've now booted the second commit built from ostree-2.conf, which
+includes the hello package.
--- /dev/null
+#!/bin/bash -e
+
+# deb-ostree-builder - Build bootable Debian OSTree commits
+#
+# Copyright (C) 2017 Dan Nicholson <nicholson@endlessm.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+PROG=$(readlink -f "$0")
+PROGDIR=$(dirname "$PROG")
+
+# Defaults
+ARCH=$(dpkg --print-architecture)
+BUILDDIR=
+GPG_SIGN=()
+GPG_HOMEDIR=
+
+usage() {
+ cat <<EOF
+Usage: $0 [OPTION...] CONFIG SUITE REPO
+
+ -a, --arch build architecture
+ -d, --dir build directory
+ --gpg-sign GPG key ID to use for signing
+ --gpg-homedir GPG homedir to find keys
+ -h, --help show this message and exit
+
+deb-ostree-builder constructs a Debian OS for use as a bootable
+OSTree. It uses debootstrap to construct the OS, adjusts it to be
+compatible with OSTree, and then commits it to a repository.
+
+CONFIG is a multistrap configuration file. SUITE is the distribution
+codename. This is used for the OSTree ref and must match the
+multistrap configuration. REPO is the path the the OSTree repository
+where the commit will be made.
+EOF
+}
+
+ARGS=$(getopt -n "$0" \
+ -o a:d:h \
+ -l arch:,dir:,gpg-sign:,gpg-homedir:,help \
+ -- "$@")
+eval set -- "$ARGS"
+
+while true; do
+ case "$1" in
+ -a|--arch)
+ ARCH=$2
+ shift 2
+ ;;
+ -d|--dir)
+ BUILDDIR=$2
+ shift 2
+ ;;
+ --gpg-sign)
+ GPG_SIGN+=($2)
+ shift 2
+ ;;
+ --gpg-homedir)
+ GPG_HOMEDIR=$2
+ shift 2
+ ;;
+ -h|--help)
+ usage
+ exit 0
+ ;;
+ --)
+ shift
+ break
+ ;;
+ esac
+done
+
+if [ $# -lt 3 ]; then
+ echo "Must specify CONFIG, SUITE and REPO" >&2
+ exit 1
+fi
+
+CONFIG=$1
+SUITE=$2
+REPO=$3
+
+# Mount cleanup handler
+DEVICES_MOUNTED=false
+cleanup_mounts()
+{
+ if $DEVICES_MOUNTED; then
+ echo "Unmounting filesystems in $BUILDDIR"
+ for dir in dev/pts dev sys proc; do
+ umount "$BUILDDIR/$dir"
+ done
+ DEVICES_MOUNTED=false
+ fi
+}
+
+# Exit handler
+TMP_BUILDDIR=
+cleanup()
+{
+ cleanup_mounts || true
+ if [ -n "$TMP_BUILDDIR" ]; then
+ rm -rf "$TMP_BUILDDIR"
+ fi
+}
+trap cleanup EXIT
+
+if [ -n "$BUILDDIR" ]; then
+ # Create specified build directory
+ echo "Creating $BUILDDIR"
+ mkdir -p "$BUILDDIR"
+else
+ # Create a temporary build directory in /var/tmp since it could be
+ # fairly large
+ TMP_BUILDDIR=$(mktemp -d -p /var/tmp deb-ostree-builder-XXXXXXXX)
+ BUILDDIR=$TMP_BUILDDIR
+ echo "Using temporary directory $BUILDDIR for build"
+fi
+
+# Ensure that dracut makes generic initramfs instead of looking just
+# at the host configuration. This is also in the dracut-config-generic
+# package, but that only gets installed after dracut makes the first
+# initramfs.
+echo "Configuring dracut for generic initramfs"
+mkdir -p "$BUILDDIR"/etc/dracut.conf.d
+cat > "$BUILDDIR"/etc/dracut.conf.d/90-deb-ostree.conf <<EOF
+# Don't make host-specific initramfs
+hostonly=no
+EOF
+
+# Define a temporary policy-rc.d that ensures that no daemons are
+# launched from the installation.
+mkdir -p "$BUILDDIR"/usr/sbin
+cat > "$BUILDDIR"/usr/sbin/policy-rc.d <<EOF
+#!/bin/sh
+exit 101
+EOF
+chmod +x "$BUILDDIR"/usr/sbin/policy-rc.d
+
+# Mount common kernel filesystems. dracut expects /dev to be mounted.
+echo "Mounting filesystems in $BUILDDIR"
+DEVICES_MOUNTED=true
+for dir in proc sys dev dev/pts; do
+ mkdir -p "$BUILDDIR/$dir"
+ mount --bind "/$dir" "$BUILDDIR/$dir"
+done
+
+# Build with multistrap
+echo "Building system with multistrap in $BUILDDIR"
+multistrap -f "$CONFIG" -d "$BUILDDIR"
+
+# All done with filesystems
+cleanup_mounts
+
+# Remove temporary policy-rc.d
+rm -f "$BUILDDIR"/usr/sbin/policy-rc.d
+
+# Cleanup cruft
+echo "Preparing system for OSTree"
+rm -rf \
+ "$BUILDDIR"/boot/*.bak \
+ "$BUILDDIR"/etc/apt/sources.list~ \
+ "$BUILDDIR"/etc/apt/trusted.gpg~ \
+ "$BUILDDIR"/etc/{passwd,group,shadow,gshadow}- \
+ "$BUILDDIR"/var/cache/debconf/*-old \
+ "$BUILDDIR"/var/lib/dpkg/*-old \
+ "$BUILDDIR"/boot/{initrd.img,vmlinuz} \
+ "$BUILDDIR"/{initrd.img,vmlinuz}{,.old}
+
+# Remove dbus machine ID cache (makes each system unique)
+rm -f "$BUILDDIR"/var/lib/dbus/machine-id "$BUILDDIR"/etc/machine-id
+
+# Remove resolv.conf copied from the host by debootstrap. The settings
+# are only valid on the target host and will be populated at runtime.
+rm -f "$BUILDDIR"/etc/resolv.conf
+
+# Remove temporary files
+rm -rf "$BUILDDIR"/var/cache/man/*
+rm -rf "$BUILDDIR"/tmp "$BUILDDIR"/var/tmp
+mkdir -p "$BUILDDIR"/tmp "$BUILDDIR"/var/tmp
+chmod 1777 "$BUILDDIR"/tmp "$BUILDDIR"/var/tmp
+
+# OSTree uses a single checksum of the combined kernel and initramfs
+# to manage boot. Determine the checksum and rename the files the way
+# OSTree expects.
+echo "Renaming kernel and initramfs per OSTree requirements"
+pushd "$BUILDDIR"/boot >/dev/null
+
+vmlinuz_match=(vmlinuz*)
+vmlinuz_file=${vmlinuz_match[0]}
+initrd_match=(initrd.img* initramfs*)
+initrd_file=${initrd_match[0]}
+
+csum=$(cat ${vmlinuz_file} ${initrd_file} | \
+ sha256sum --binary | \
+ awk '{print $1}')
+echo "OSTree boot checksum: ${csum}"
+
+mv ${vmlinuz_file} ${vmlinuz_file}-${csum}
+mv ${initrd_file} ${initrd_file/initrd.img/initramfs}-${csum}
+
+popd >/dev/null
+
+# OSTree only commits files or symlinks
+rm -rf "$BUILDDIR"/dev
+mkdir -p "$BUILDDIR"/dev
+
+# Fixup home directory base paths for OSTree
+sed -i -e 's|DHOME=/home|DHOME=/sysroot/home|g' \
+ "${BUILDDIR}"/etc/adduser.conf
+sed -i -e 's|# HOME=/home|HOME=/sysroot/home|g' \
+ "${BUILDDIR}"/etc/default/useradd
+
+# Move /etc to /usr/etc.
+#
+# FIXME: Need to handle passwd and group to be updatable. This can be
+# done with libnss-altfiles, though that has other drawbacks.
+if [ -d "${BUILDDIR}"/usr/etc ]; then
+ echo "ERROR: Non-empty /usr/etc found!" >&2
+ ls -lR "${BUILDDIR}"/usr/etc
+ exit 1
+fi
+mv "${BUILDDIR}"/etc "${BUILDDIR}"/usr
+
+# Move dpkg database to /usr so it's accessible after the OS /var is
+# mounted, but make a symlink so it works without modifications to dpkg
+# or apt
+mkdir -p "${BUILDDIR}"/usr/share/dpkg
+if [ -e "${BUILDDIR}"/usr/share/dpkg/database ]; then
+ echo "ERROR: /usr/share/dpkg/database already exists!" >&2
+ ls -lR "${BUILDDIR}"/usr/share/dpkg/database >&2
+ exit 1
+fi
+mv "${BUILDDIR}"/var/lib/dpkg "${BUILDDIR}"/usr/share/dpkg/database
+ln -sr "${BUILDDIR}"/usr/share/dpkg/database \
+ "${BUILDDIR}"/var/lib/dpkg
+
+# tmpfiles.d setup to make the ostree root compatible with persistent
+# directories in the sysroot.
+cat > "${BUILDDIR}"/usr/lib/tmpfiles.d/ostree.conf <<EOF
+d /sysroot/home 0755 root root -
+d /sysroot/root 0700 root root -
+d /var/opt 0755 root root -
+d /var/local 0755 root root -
+d /run/media 0755 root root -
+L /var/lib/dpkg - - - - ../../usr/share/dpkg/database
+EOF
+
+# Create symlinks in the ostree for persistent directories.
+mkdir -p "${BUILDDIR}"/sysroot
+rm -rf "${BUILDDIR}"/{home,root,media,opt} "${BUILDDIR}"/usr/local
+ln -s /sysroot/ostree "${BUILDDIR}"/ostree
+ln -s /sysroot/home "${BUILDDIR}"/home
+ln -s /sysroot/root "${BUILDDIR}"/root
+ln -s /var/opt "${BUILDDIR}"/opt
+ln -s /var/local "${BUILDDIR}"/usr/local
+ln -s /run/media "${BUILDDIR}"/media
+
+# Now ready to commit. Make the repo if necessary. An archive-z2 repo
+# is used since the intention is to use this repo to serve updates
+# from.
+mkdir -p "$REPO"
+if [ ! -f "$REPO"/config ]; then
+ echo "Initialiazing OSTree repo $REPO"
+ ostree --repo="$REPO" init --mode=archive-z2
+fi
+
+# Make the commit. The ostree ref is flatpak style.
+branch="os/debian/$ARCH/$SUITE"
+COMMIT_OPTS=(
+ --repo="$REPO"
+ --branch="$branch"
+ --subject="Build $SUITE $ARCH $(date --iso-8601=seconds)"
+ --skip-if-unchanged
+ --table-output
+)
+for id in ${GPG_SIGN[@]}; do
+ COMMIT_OPTS+=(--gpg-sign="$id")
+done
+if [ -n "$GPG_HOMEDIR" ]; then
+ COMMIT_OPTS+=(--gpg-homedir="$GPG_HOMEDIR")
+fi
+echo "Committing $BUILDDIR to $REPO branch $branch"
+ostree commit "${COMMIT_OPTS[@]}" "$BUILDDIR"
+
+# Update the repo summary
+SUMMARY_OPTS=(
+ --repo="$REPO"
+ --update
+)
+for id in ${GPG_SIGN[@]}; do
+ SUMMARY_OPTS+=(--gpg-sign="$id")
+done
+if [ -n "$GPG_HOMEDIR" ]; then
+ SUMMARY_OPTS+=(--gpg-homedir="$GPG_HOMEDIR")
+fi
+echo "Updating $REPO summary file"
+ostree summary "${SUMMARY_OPTS[@]}"
--- /dev/null
+#!/bin/bash -e
+
+# deb-ostree-builder - Build bootable Debian OSTree commits
+# This version has been modified to install extra packages from
+# /root/extra-packages.
+#
+# Copyright (C) 2017 Dan Nicholson <nicholson@endlessm.com>
+# Copyright (C) 2019 Simon McVittie
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+PROG=$(readlink -f "$0")
+PROGDIR=$(dirname "$PROG")
+
+# Defaults
+ARCH=$(dpkg --print-architecture)
+BUILDDIR=
+GPG_SIGN=()
+GPG_HOMEDIR=
+
+usage() {
+ cat <<EOF
+Usage: $0 [OPTION...] CONFIG SUITE REPO
+
+ -a, --arch build architecture
+ -d, --dir build directory
+ --gpg-sign GPG key ID to use for signing
+ --gpg-homedir GPG homedir to find keys
+ -h, --help show this message and exit
+
+deb-ostree-builder constructs a Debian OS for use as a bootable
+OSTree. It uses debootstrap to construct the OS, adjusts it to be
+compatible with OSTree, and then commits it to a repository.
+
+CONFIG is a multistrap configuration file. SUITE is the distribution
+codename. This is used for the OSTree ref and must match the
+multistrap configuration. REPO is the path the the OSTree repository
+where the commit will be made.
+EOF
+}
+
+ARGS=$(getopt -n "$0" \
+ -o a:d:h \
+ -l arch:,dir:,gpg-sign:,gpg-homedir:,help \
+ -- "$@")
+eval set -- "$ARGS"
+
+while true; do
+ case "$1" in
+ -a|--arch)
+ ARCH=$2
+ shift 2
+ ;;
+ -d|--dir)
+ BUILDDIR=$2
+ shift 2
+ ;;
+ --gpg-sign)
+ GPG_SIGN+=($2)
+ shift 2
+ ;;
+ --gpg-homedir)
+ GPG_HOMEDIR=$2
+ shift 2
+ ;;
+ -h|--help)
+ usage
+ exit 0
+ ;;
+ --)
+ shift
+ break
+ ;;
+ esac
+done
+
+if [ $# -lt 3 ]; then
+ echo "Must specify CONFIG, SUITE and REPO" >&2
+ exit 1
+fi
+
+CONFIG=$1
+SUITE=$2
+REPO=$3
+
+# Mount cleanup handler
+DEVICES_MOUNTED=false
+cleanup_mounts()
+{
+ if $DEVICES_MOUNTED; then
+ echo "Unmounting filesystems in $BUILDDIR"
+ for dir in dev/pts dev sys proc; do
+ umount "$BUILDDIR/$dir"
+ done
+ DEVICES_MOUNTED=false
+ fi
+}
+
+# Exit handler
+TMP_BUILDDIR=
+cleanup()
+{
+ cleanup_mounts || true
+ if [ -n "$TMP_BUILDDIR" ]; then
+ rm -rf "$TMP_BUILDDIR"
+ fi
+}
+trap cleanup EXIT
+
+if [ -n "$BUILDDIR" ]; then
+ # Create specified build directory
+ echo "Creating $BUILDDIR"
+ mkdir -p "$BUILDDIR"
+else
+ # Create a temporary build directory in /var/tmp since it could be
+ # fairly large
+ TMP_BUILDDIR=$(mktemp -d -p /var/tmp deb-ostree-builder-XXXXXXXX)
+ BUILDDIR=$TMP_BUILDDIR
+ echo "Using temporary directory $BUILDDIR for build"
+fi
+
+# Ensure that dracut makes generic initramfs instead of looking just
+# at the host configuration. This is also in the dracut-config-generic
+# package, but that only gets installed after dracut makes the first
+# initramfs.
+echo "Configuring dracut for generic initramfs"
+mkdir -p "$BUILDDIR"/etc/dracut.conf.d
+cat > "$BUILDDIR"/etc/dracut.conf.d/90-deb-ostree.conf <<EOF
+# Don't make host-specific initramfs
+hostonly=no
+EOF
+
+# Define a temporary policy-rc.d that ensures that no daemons are
+# launched from the installation.
+mkdir -p "$BUILDDIR"/usr/sbin
+cat > "$BUILDDIR"/usr/sbin/policy-rc.d <<EOF
+#!/bin/sh
+exit 101
+EOF
+chmod +x "$BUILDDIR"/usr/sbin/policy-rc.d
+
+# Mount common kernel filesystems. dracut expects /dev to be mounted.
+echo "Mounting filesystems in $BUILDDIR"
+DEVICES_MOUNTED=true
+for dir in proc sys dev dev/pts; do
+ mkdir -p "$BUILDDIR/$dir"
+ mount --bind "/$dir" "$BUILDDIR/$dir"
+done
+
+# Build with multistrap
+echo "Building system with multistrap in $BUILDDIR"
+multistrap -f "$CONFIG" -d "$BUILDDIR"
+
+# This is a hack for testing ostree-boot before it is in the Debian archive
+if [ -d /root/extra-packages ]; then
+ mkdir "$BUILDDIR/root/extra-packages"
+ cp /root/extra-packages/*.deb "$BUILDDIR/root/extra-packages"
+ chroot "$BUILDDIR" apt -y update
+ chroot "$BUILDDIR" apt -y install /root/extra-packages/*.deb
+ rm -fr "$BUILDDIR/root/extra-packages"
+fi
+
+# All done with filesystems
+cleanup_mounts
+
+# Remove temporary policy-rc.d
+rm -f "$BUILDDIR"/usr/sbin/policy-rc.d
+
+# Cleanup cruft
+echo "Preparing system for OSTree"
+rm -rf \
+ "$BUILDDIR"/boot/*.bak \
+ "$BUILDDIR"/etc/apt/sources.list~ \
+ "$BUILDDIR"/etc/apt/trusted.gpg~ \
+ "$BUILDDIR"/etc/{passwd,group,shadow,gshadow}- \
+ "$BUILDDIR"/var/cache/debconf/*-old \
+ "$BUILDDIR"/var/lib/dpkg/*-old \
+ "$BUILDDIR"/boot/{initrd.img,vmlinuz} \
+ "$BUILDDIR"/{initrd.img,vmlinuz}{,.old}
+
+# Remove dbus machine ID cache (makes each system unique)
+rm -f "$BUILDDIR"/var/lib/dbus/machine-id "$BUILDDIR"/etc/machine-id
+
+# Remove resolv.conf copied from the host by debootstrap. The settings
+# are only valid on the target host and will be populated at runtime.
+rm -f "$BUILDDIR"/etc/resolv.conf
+
+# Remove temporary files
+rm -rf "$BUILDDIR"/var/cache/man/*
+rm -rf "$BUILDDIR"/tmp "$BUILDDIR"/var/tmp
+mkdir -p "$BUILDDIR"/tmp "$BUILDDIR"/var/tmp
+chmod 1777 "$BUILDDIR"/tmp "$BUILDDIR"/var/tmp
+
+# OSTree uses a single checksum of the combined kernel and initramfs
+# to manage boot. Determine the checksum and rename the files the way
+# OSTree expects.
+echo "Renaming kernel and initramfs per OSTree requirements"
+pushd "$BUILDDIR"/boot >/dev/null
+
+vmlinuz_match=(vmlinuz*)
+vmlinuz_file=${vmlinuz_match[0]}
+initrd_match=(initrd.img* initramfs*)
+initrd_file=${initrd_match[0]}
+
+csum=$(cat ${vmlinuz_file} ${initrd_file} | \
+ sha256sum --binary | \
+ awk '{print $1}')
+echo "OSTree boot checksum: ${csum}"
+
+mv ${vmlinuz_file} ${vmlinuz_file}-${csum}
+mv ${initrd_file} ${initrd_file/initrd.img/initramfs}-${csum}
+
+popd >/dev/null
+
+# OSTree only commits files or symlinks
+rm -rf "$BUILDDIR"/dev
+mkdir -p "$BUILDDIR"/dev
+
+# Fixup home directory base paths for OSTree
+sed -i -e 's|DHOME=/home|DHOME=/sysroot/home|g' \
+ "${BUILDDIR}"/etc/adduser.conf
+sed -i -e 's|# HOME=/home|HOME=/sysroot/home|g' \
+ "${BUILDDIR}"/etc/default/useradd
+
+# Move /etc to /usr/etc.
+#
+# FIXME: Need to handle passwd and group to be updatable. This can be
+# done with libnss-altfiles, though that has other drawbacks.
+if [ -d "${BUILDDIR}"/usr/etc ]; then
+ echo "ERROR: Non-empty /usr/etc found!" >&2
+ ls -lR "${BUILDDIR}"/usr/etc
+ exit 1
+fi
+mv "${BUILDDIR}"/etc "${BUILDDIR}"/usr
+
+# Move dpkg database to /usr so it's accessible after the OS /var is
+# mounted, but make a symlink so it works without modifications to dpkg
+# or apt
+mkdir -p "${BUILDDIR}"/usr/share/dpkg
+if [ -e "${BUILDDIR}"/usr/share/dpkg/database ]; then
+ echo "ERROR: /usr/share/dpkg/database already exists!" >&2
+ ls -lR "${BUILDDIR}"/usr/share/dpkg/database >&2
+ exit 1
+fi
+mv "${BUILDDIR}"/var/lib/dpkg "${BUILDDIR}"/usr/share/dpkg/database
+ln -sr "${BUILDDIR}"/usr/share/dpkg/database \
+ "${BUILDDIR}"/var/lib/dpkg
+
+# tmpfiles.d setup to make the ostree root compatible with persistent
+# directories in the sysroot.
+cat > "${BUILDDIR}"/usr/lib/tmpfiles.d/ostree.conf <<EOF
+d /sysroot/home 0755 root root -
+d /sysroot/root 0700 root root -
+d /var/opt 0755 root root -
+d /var/local 0755 root root -
+d /run/media 0755 root root -
+L /var/lib/dpkg - - - - ../../usr/share/dpkg/database
+EOF
+
+# Create symlinks in the ostree for persistent directories.
+mkdir -p "${BUILDDIR}"/sysroot
+rm -rf "${BUILDDIR}"/{home,root,media,opt} "${BUILDDIR}"/usr/local
+ln -s /sysroot/ostree "${BUILDDIR}"/ostree
+ln -s /sysroot/home "${BUILDDIR}"/home
+ln -s /sysroot/root "${BUILDDIR}"/root
+ln -s /var/opt "${BUILDDIR}"/opt
+ln -s /var/local "${BUILDDIR}"/usr/local
+ln -s /run/media "${BUILDDIR}"/media
+
+# Now ready to commit. Make the repo if necessary. An archive-z2 repo
+# is used since the intention is to use this repo to serve updates
+# from.
+mkdir -p "$REPO"
+if [ ! -f "$REPO"/config ]; then
+ echo "Initialiazing OSTree repo $REPO"
+ ostree --repo="$REPO" init --mode=archive-z2
+fi
+
+# Make the commit. The ostree ref is flatpak style.
+branch="os/debian/$ARCH/$SUITE"
+COMMIT_OPTS=(
+ --repo="$REPO"
+ --branch="$branch"
+ --subject="Build $SUITE $ARCH $(date --iso-8601=seconds)"
+ --skip-if-unchanged
+ --table-output
+)
+for id in ${GPG_SIGN[@]}; do
+ COMMIT_OPTS+=(--gpg-sign="$id")
+done
+if [ -n "$GPG_HOMEDIR" ]; then
+ COMMIT_OPTS+=(--gpg-homedir="$GPG_HOMEDIR")
+fi
+echo "Committing $BUILDDIR to $REPO branch $branch"
+ostree commit "${COMMIT_OPTS[@]}" "$BUILDDIR"
+
+# Update the repo summary
+SUMMARY_OPTS=(
+ --repo="$REPO"
+ --update
+)
+for id in ${GPG_SIGN[@]}; do
+ SUMMARY_OPTS+=(--gpg-sign="$id")
+done
+if [ -n "$GPG_HOMEDIR" ]; then
+ SUMMARY_OPTS+=(--gpg-homedir="$GPG_HOMEDIR")
+fi
+echo "Updating $REPO summary file"
+ostree summary "${SUMMARY_OPTS[@]}"
--- /dev/null
+[general]
+arch=amd64
+noauth=false
+aptsources=debian
+bootstrap=debian
+addimportant=true
+cleanup=true
+
+[debian]
+packages=linux-image-amd64 grub-pc dracut ostree-boot
+# to boot root partitions on LVM
+packages=lvm2
+# usrmerge is required by the builder script
+packages=usrmerge
+source=http://deb.debian.org/debian
+keyring=debian-archive-keyring
+suite=sid
--- /dev/null
+[general]
+arch=amd64
+noauth=false
+aptsources=debian
+bootstrap=debian
+addimportant=true
+cleanup=true
+
+[debian]
+packages=linux-image-amd64 grub-pc dracut ostree-boot
+# to boot root partitions on LVM
+packages=lvm2
+# usrmerge is required by the builder script
+packages=usrmerge
+# an extra package to verify deployment change
+packages=hello
+source=http://deb.debian.org/debian
+keyring=debian-archive-keyring
+suite=sid